package com.wang.common.security.service;

import com.wang.common.core.domain.LoginUser;
import com.wang.common.core.utils.JWTUtil;
import com.wang.common.core.constants.CacheConstants;
import com.wang.common.core.constants.JWTConstants;
import com.wang.common.redis.service.RedisService;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class TokenService {
    @Autowired
    private RedisService redisService;

    public String createToken(Long userId, Integer identity, String nickName, String headImage, String secret){

        //生成 JWT token 的 Payload 中存储的信息
        Map<String,Object> claim = new HashMap<>();
        claim.put(JWTConstants.USER_ID, userId); //放入用户id


        //把用户信息存储到Redis中,存储序列化用户信息
        // key:
        String key = CacheConstants.LOGIN_TOKEN_KEY + userId;
        // value:
        LoginUser loginUser = new LoginUser();
        loginUser.setIdentity(identity); //身份
        loginUser.setNickName(nickName); //昵称
        loginUser.setHeadImage(headImage); //头像

        redisService.setCacheObject(key,loginUser,CacheConstants.EXP, TimeUnit.MINUTES);

        //返回用户token
        return JWTUtil.createToken(claim,secret);
    }

    /**
     * 延长token时长
     * @param token 传入token
     * @param secret 传入密钥
     */
    public void extendTokenTime(String token,String secret){
        //解析userId
        Long userId = getUserId(token,secret);
        if (userId == null){
            return;
        }
        //获取剩余的时间
        String cacheKey = CacheConstants.LOGIN_TOKEN_KEY + userId;
        Long expire = redisService.getExpire(cacheKey);

        if (expire != null && expire < CacheConstants.REFRESH_TIME){
            //如果剩余时间小于
            //重置Redis中的用户token剩余时间
            redisService.expire(cacheKey,CacheConstants.EXP,TimeUnit.MINUTES);
        }
    }

    /**
     * 获取当前用户信息
     * @param token 用户令牌
     * @param secret 签名密钥
     * @return 返回从Redis中获取的用户信息
     */
    public LoginUser getLoginUser(String token, String secret){
        //解析UserId
        Long userId = getUserId(token, secret);

        //如果userId为空,说明缓存中没有该用户的信息 --> 直接返回null
        if (userId == null){
            return null;
        }

        //从Redis中获取用户信息
        //获取key
        String cacheKey = CacheConstants.LOGIN_TOKEN_KEY + userId;
        ///根据key从redis中获取实际用户信息并返回
        return redisService.getCacheObject(cacheKey, LoginUser.class);
    }

    /**
     * 从Redis中删除当前用户信息
     * @param token 用户令牌
     * @param secret 签名密钥
     * @return 返回是否删除成功
     */
    public boolean deleteLoginUser(String token,String secret){
        Long userId = getUserId(token, secret);

        //userId解析失败
        if (userId == null){
            return false;
        }
        //获取key
        String cacheKey = CacheConstants.LOGIN_TOKEN_KEY + userId;
        return redisService.deleteObject(cacheKey);//返回是否删除成功
    }

    /**
     * 刷新redis中的用户信息
     * @param nickName 昵称
     * @param headImage 用户头像
     * @param userId userId
     */
    public void refreshLoginUser(String nickName,String headImage,Long userId){

        String tokenKey = getTokenKey(userId);

        LoginUser loginUser = redisService.getCacheObject(tokenKey, LoginUser.class);
        loginUser.setNickName(nickName);
        loginUser.setHeadImage(headImage);

        redisService.setCacheObject(tokenKey,loginUser);
    }


    /**
     * 从claim中获取用户id
     * @param token token
     * @param secret 签名密钥
     * @return 返回userId
     */
    public Long getUserId(String token,String secret){
        //进行token解析
        Claims claims = getClaims(token, secret);
        if (claims == null) return null;
        //获取token中的UserId
        return Long.valueOf(JWTUtil.getUserId(claims));
    }

    /**
     * 从用户的token中解析出用户信息的Claim
     * @param token 用户token
     * @param secret 签名密钥
     * @return 返回Claim
     */
    public Claims getClaims(String token, String secret) {
        Claims claims;
        try {
            claims = JWTUtil.parseToken(token, secret);
            if (claims == null){
                log.error("token不可以为空");
                return null;
            }
        }catch (Exception e){
            log.error("token解析异常");
            return null;
        }
        return claims;
    }

    public String getTokenKey(Long userId){
        return CacheConstants.LOGIN_TOKEN_KEY + userId;
    }
}